package com.itheima.stock.security.config;


import com.itheima.stock.security.filter.AuthenticationFilter;
import com.itheima.stock.security.filter.JwtLoginAuthenticationFilter;
import com.itheima.stock.security.handler.MyAccessDeniedHandler;
import com.itheima.stock.security.handler.MyAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity//开启web安全设置生效
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启对springSecurity注解功能支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 构建认证服务，并将对象注入spring IOC容器，用户登录时，会调用该服务进行用户合法信息认证
     * @return
     */

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 定义公共的无需被拦截的资源
     * @return
     */
    private String[] getPubPath(){
        //公共访问资源
        String[] urls = {
                "/**/*.css","/**/*.js","/favicon.ico","/doc.html",
                "/druid/**","/webjars/**","/v2/api-docs","/api/captcha",
                "/swagger/**","/swagger-resources/**","/swagger-ui.html"
        };
        return urls;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.logout().logoutUrl("/api/logout").invalidateHttpSession(true);
        //开启允许iframe 嵌套。security默认禁用ifram跨域与缓存
        http.headers().frameOptions().disable().cacheControl().disable();
        //session禁用
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.csrf().disable();
        http.authorizeRequests()
                .antMatchers(getPubPath()).permitAll()
                .anyRequest().authenticated();
        http
                .addFilterBefore(jwtLoginAuthenticationFilter(),//自定义过滤器
                        UsernamePasswordAuthenticationFilter.class);//默认过滤器
        http
                .addFilterBefore(authenticationFilter(),JwtLoginAuthenticationFilter.class);
        http
                .exceptionHandling()
        .accessDeniedHandler(new MyAccessDeniedHandler())
        .authenticationEntryPoint(new MyAuthenticationEntryPoint());
    }

    /**
     * 自定义认证过滤器
     *      隐含:如果认证成功,则在安全上下文中维护认证相关信息
     *          如果上下文中存在,则默认的usernamePasswordAuthenticationFilter没必要在认证
     *          所以执行顺序自定义额在前,一旦成功则默认的就不用执行了
     * @return
     * @throws Exception
     */
    @Bean
    public JwtLoginAuthenticationFilter jwtLoginAuthenticationFilter() throws Exception {
        //构造认证过滤器对象,并设置认证路径/myLogin
        JwtLoginAuthenticationFilter authenticationFilter = new JwtLoginAuthenticationFilter("/api/login");
        //设置认证过滤器bean
        authenticationFilter.setAuthenticationManager(authenticationManagerBean());
        authenticationFilter.setRedisTemplate(redisTemplate);
        return authenticationFilter;//配置完之后执行MyUsernamePasswordAuthenticationFilter
    }

    /**
     * 自定义授权过滤器
     * 过滤一切被访问的资源
     * @return
     */
    @Bean
    public AuthenticationFilter authenticationFilter(){
        AuthenticationFilter filter = new AuthenticationFilter();
        return filter;
    }


    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

}